home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 14228 / 14228.xpi / chrome / content / metaData.js next >
Text File  |  2009-04-23  |  18KB  |  617 lines

  1. //@line 41 "e:\builds\moz2_slave\win32_build\build\browser\base\content\metaData.js"
  2.  
  3. const XLinkNS = "http://www.w3.org/1999/xlink";
  4. const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  5. const XMLNS = "http://www.w3.org/XML/1998/namespace";
  6. const XHTMLNS = "http://www.w3.org/1999/xhtml";
  7. var gMetadataBundle;
  8. var gLangBundle;
  9. var gRegionBundle;
  10. var nodeView;
  11. var htmlMode = false;
  12.  
  13. var onLink   = false;
  14. var onImage  = false;
  15. var onInsDel = false;
  16. var onQuote  = false;
  17. var onMisc   = false;
  18. var onTable  = false;
  19. var onTitle  = false;
  20. var onLang   = false;
  21.  
  22. // Interface for image loading content
  23. const nsIImageLoadingContent = Components.interfaces.nsIImageLoadingContent;
  24.  
  25. const prefs = Components.classes["@mozilla.org/preferences-service;1"].
  26.               getService(Components.interfaces.nsIPrefBranch);
  27.  
  28. const nsICacheService = Components.interfaces.nsICacheService;
  29. const cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
  30.                      .getService(nsICacheService);
  31. var httpCacheSession = cacheService.createSession("HTTP", 0, true);
  32. httpCacheSession.doomEntriesIfExpired = false;
  33. var ftpCacheSession = cacheService.createSession("FTP", 0, true);
  34. ftpCacheSession.doomEntriesIfExpired = false;
  35.  
  36. const PREF_PINGS_ENABLED = "browser.send_pings";
  37. const PREF_PINGS_MAX_PER_LINK = "browser.send_pings.max_per_link";
  38. const PREF_PINGS_REQUIRE_SAME_HOST = "browser.send_pings.require_same_host";
  39.  
  40. /**
  41.  * This function generates an array of pings that will be sent if the given
  42.  * anchor element is clicked.  It basically duplicates the pref checking logic
  43.  * found in nsWebShell.cpp.  It might be nice to expose that functionality on
  44.  * some interface that both of these sections of code could share.
  45.  *
  46.  * @param elem
  47.  *   An anchor or area element
  48.  * @return 
  49.  *   An array of URL strings corresponding to the pings that would occur if
  50.  *   the element's href were loaded.
  51.  */
  52. function getPings(elem)
  53. {
  54.   var result = [];
  55.  
  56.   var enabled = prefs.getBoolPref(PREF_PINGS_ENABLED);
  57.   if (!enabled)
  58.     return result;
  59.   var maxPings = prefs.getIntPref(PREF_PINGS_MAX_PER_LINK);
  60.   if (maxPings == 0)
  61.     return result;
  62.   var requireSameHost = prefs.getBoolPref(PREF_PINGS_REQUIRE_SAME_HOST);
  63.  
  64.   const ios =
  65.       Components.classes["@mozilla.org/network/io-service;1"].
  66.       getService(Components.interfaces.nsIIOService);
  67.  
  68.   var doc = elem.ownerDocument;
  69.   var docURI = ios.newURI(doc.documentURI, doc.characterSet, null);
  70.  
  71.   // The URL strings returned by elem.ping are absolute URLs.
  72.   var pings = elem.ping;
  73.   if (!pings)
  74.     return result;
  75.   pings = pings.split(" ");
  76.   for (var i = 0; i < pings.length; ++i) {
  77.     if (requireSameHost) {
  78.       var uri = ios.newURI(pings[i], doc.characterSet, null);
  79.       if (uri.asciiHost == docURI.asciiHost)
  80.         result.push(pings[i]);
  81.     } else {
  82.       result.push(pings[i]);
  83.     }
  84.     if (result.length == maxPings)
  85.       break;
  86.   }
  87.  
  88.   return result;
  89. }
  90.  
  91. function onLoad()
  92. {
  93.   gMetadataBundle = document.getElementById("bundle_metadata");
  94.   gLangBundle = document.getElementById("bundle_languages");
  95.   gRegionBundle = document.getElementById("bundle_regions");
  96.   
  97.   showMetadataFor(window.arguments[0]);
  98.   nodeView = window.arguments[0].ownerDocument.defaultView;
  99. }
  100.  
  101. function showMetadataFor(elem)
  102. {
  103.   // skip past non-element nodes
  104.   while (elem && elem.nodeType != Node.ELEMENT_NODE)
  105.     elem = elem.parentNode;
  106.  
  107.   if (!elem) {
  108.     alert(gMetadataBundle.getString("unableToShowProps"));
  109.     window.close();
  110.   }
  111.  
  112.   if (elem.ownerDocument.getElementsByName && !elem.ownerDocument.namespaceURI)
  113.     htmlMode = true;
  114.   
  115.   // htmllocalname is "" if it's not an html tag, or the name of the tag if it is.
  116.   var htmllocalname = "";
  117.   if (isHTMLElement(elem,"")) { 
  118.     htmllocalname = elem.localName.toLowerCase();
  119.   }
  120.   
  121.   // We only look for images once
  122.   checkForImage(elem, htmllocalname);
  123.   
  124.   // Walk up the tree, looking for elements of interest.
  125.   // Each of them could be at a different level in the tree, so they each
  126.   // need their own boolean to tell us to stop looking.
  127.   while (elem && elem.nodeType == Node.ELEMENT_NODE) {
  128.     htmllocalname = "";
  129.     if (isHTMLElement(elem,"")) { 
  130.       htmllocalname = elem.localName.toLowerCase();
  131.     }
  132.  
  133.     if (!onLink)   checkForLink(elem, htmllocalname);
  134.     if (!onInsDel) checkForInsDel(elem, htmllocalname);
  135.     if (!onQuote)  checkForQuote(elem, htmllocalname);
  136.     if (!onTable)  checkForTable(elem, htmllocalname);
  137.     if (!onTitle)  checkForTitle(elem, htmllocalname);
  138.     if (!onLang)   checkForLang(elem, htmllocalname);
  139.       
  140.     elem = elem.parentNode;
  141.   }
  142.   
  143.   // Decide which sections to show
  144.   var onMisc = onTable || onTitle || onLang;
  145.   if (!onMisc)   hideNode("misc-sec");
  146.   if (!onLink)   hideNode("link-sec");
  147.   if (!onImage)  hideNode("image-sec");
  148.   if (!onInsDel) hideNode("insdel-sec");
  149.   if (!onQuote)  hideNode("quote-sec");
  150.  
  151.   // Fix the Misc section visibilities
  152.   if (onMisc) {
  153.     if (!onTable) hideNode("misc-tblsummary");
  154.     if (!onLang)  hideNode("misc-lang");
  155.     if (!onTitle) hideNode("misc-title");
  156.   }
  157.  
  158.   // Get rid of the "No properties" message. This is a backstop -
  159.   // it should really never show, as long as nsContextMenu.js's
  160.   // checking doesn't get broken.
  161.   if (onLink || onImage || onInsDel || onQuote || onMisc)
  162.     hideNode("no-properties")
  163. }
  164.  
  165.  
  166. function checkForImage(elem, htmllocalname)
  167. {
  168.   var img;
  169.   var imgType; // "img" = <img>
  170.                // "object" = <object>
  171.                // "input" = <input type=image>
  172.                // "background" = css background (to be added later)
  173.   var ismap = false;
  174.  
  175.   if (htmllocalname === "img") {
  176.     img = elem;
  177.     imgType = "img";
  178.  
  179.   } else if (htmllocalname === "object" &&
  180.              elem.type.substring(0,6) == "image/" &&
  181.              elem.data) {
  182.     img = elem;
  183.     imgType = "object";
  184.  
  185.   } else if (htmllocalname === "input" &&
  186.              elem.type.toUpperCase() == "IMAGE") {
  187.     img = elem;
  188.     imgType = "input";
  189.  
  190.   } else if (htmllocalname === "area" || htmllocalname === "a") {
  191.  
  192.     // Clicked in image map?
  193.     var map = elem;
  194.     ismap = true;
  195.     setAlt(map);
  196.  
  197.     while (map && map.nodeType == Node.ELEMENT_NODE && !isHTMLElement(map,"map") )
  198.       map = map.parentNode;
  199.  
  200.     if (map && map.nodeType == Node.ELEMENT_NODE) {
  201.       img = getImageForMap(map);
  202.       var imgLocalName = img && img.localName.toLowerCase();
  203.       if (imgLocalName == "img" || imgLocalName == "object")
  204.           imgType = imgLocalName;
  205.     }
  206.   }
  207.  
  208.   if (img) {
  209.  
  210.     var imgURL = imgType == "object" ? img.data : img.src;
  211.     setInfo("image-url", imgURL);
  212.     var size = getSize(imgURL);
  213.  
  214.     if (size != -1) {
  215.       var kbSize = size / 1024;
  216.       kbSize = Math.round(kbSize*100)/100;
  217.       setInfo("image-filesize", gMetadataBundle.getFormattedString("imageSize", [kbSize, size]));
  218.     } else {
  219.       setInfo("image-filesize", gMetadataBundle.getString("imageSizeUnknown"));
  220.     }
  221.  
  222.     var imageRequest = img.QueryInterface(nsIImageLoadingContent)
  223.                           .getRequest(nsIImageLoadingContent.CURRENT_REQUEST);
  224.     var image = imageRequest && imageRequest.image;
  225.     var imageType = "";
  226.     if (imageRequest) {
  227.       imageType = imageRequest.mimeType;
  228.       var imageMimeType = /^image\/(.*)/.exec(imageType);
  229.       if (imageMimeType) {
  230.         imageType = imageMimeType[1].toUpperCase();
  231.         if (image && image.numFrames > 1)
  232.           imageType = gMetadataBundle.getFormattedString("animatedImageType",
  233.                                                          [imageType, image.numFrames]);
  234.         else
  235.           imageType = gMetadataBundle.getFormattedString("imageType", [imageType]);
  236.       }
  237.     }
  238.     setInfo("image-type", imageType);
  239.  
  240.     var imageSize = "";
  241.     if (img.width) {
  242.       if (image && (image.width != img.width || image.height != img.height))
  243.         imageSize = gMetadataBundle.getFormattedString("imageDimensionsScaled",
  244.                                                        [image.width, image.height,
  245.                                                         img.width,   img.height]);
  246.       else
  247.         imageSize = gMetadataBundle.getFormattedString("imageDimensions", [img.width, img.height]);
  248.     }        
  249.     setInfo("image-size", imageSize);
  250.      
  251.     if (imgType == "img") {
  252.       setInfo("image-desc", img.longDesc);
  253.     } else {
  254.       setInfo("image-desc", "");
  255.     }
  256.     
  257.     onImage = true;
  258.   }
  259.  
  260.   if (!ismap) {
  261.    if (imgType == "img" || imgType == "input") {
  262.      setAlt(img);
  263.    } else {
  264.      hideNode("image-alt");
  265.    }
  266.   }
  267. }
  268.  
  269. function checkForLink(elem, htmllocalname)
  270. {
  271.   if ((htmllocalname === "a" && elem.href != "") ||
  272.     htmllocalname === "area") {
  273.  
  274.     setInfo("link-lang", convertLanguageCode(elem.getAttribute("hreflang")));
  275.     setInfo("link-url",  elem.href);
  276.     setInfo("link-type", elem.getAttribute("type"));
  277.     setInfo("link-rel",  elem.getAttribute("rel"));
  278.     setInfo("link-rev",  elem.getAttribute("rev"));
  279.     setInfo("link-ping", getPings(elem).join('\n'));
  280.  
  281.     var target = elem.target;
  282.  
  283.     switch (target) {
  284.     case "_top":
  285.       setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  286.       break;
  287.     case "_parent":
  288.       setInfo("link-target", gMetadataBundle.getString("parentFrameText"));
  289.       break;
  290.     case "_blank":
  291.       var where = "Window";
  292.       var newWindowPref = prefs.getIntPref("browser.link.open_newwindow");
  293.       if (newWindowPref == 3)
  294.         where = "Tab";
  295.       setInfo("link-target", gMetadataBundle.getString("new" + where + "Text"));
  296.       break;
  297.     case "":
  298.     case "_self":
  299.       if (elem.ownerDocument.defaultView) {
  300.         if (elem.ownerDocument != elem.ownerDocument.defaultView.content.document)
  301.           setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  302.         else
  303.           setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  304.       } else {
  305.         hideNode("link-target");
  306.       }
  307.       break;
  308.     default:
  309.       setInfo("link-target", "\"" + target + "\"");
  310.     }
  311.  
  312.     onLink = true;
  313.   }
  314.  
  315.   else if (elem.getAttributeNS(XLinkNS, "href") != "") {
  316.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  317.                               .getService(Components.interfaces.nsIIOService);
  318.     var url = elem.getAttributeNS(XLinkNS, "href");
  319.     try {
  320.         var baseURI = ioService.newURI(elem.baseURI, elem.ownerDocument.characterSet, null);
  321.         url = ioService.newURI(url, elem.ownerDocument.characterSet, baseURI).spec;
  322.     } catch (e) {}
  323.     setInfo("link-url", url);
  324.     setInfo("link-lang", "");
  325.     setInfo("link-type", "");
  326.     setInfo("link-rel", "");
  327.     setInfo("link-rev", "");
  328.     setInfo("link-ping", "");
  329.  
  330.     switch (elem.getAttributeNS(XLinkNS,"show")) {
  331.     case "embed":
  332.         setInfo("link-target", gMetadataBundle.getString("embeddedText"));
  333.         break;
  334.     case "new":
  335.         setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  336.         break;
  337.     case "":
  338.     case "replace":
  339.         if (elem.ownerDocument != elem.ownerDocument.defaultView.content.document)
  340.             setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  341.         else
  342.             setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  343.         break;
  344.     default:
  345.         setInfo("link-target", "");
  346.         break;
  347.     }
  348.     
  349.     onLink = true;
  350.   }
  351. }
  352.  
  353. function checkForInsDel(elem, htmllocalname)
  354. {
  355.   if ((htmllocalname === "ins" || htmllocalname === "del") &&
  356.     (elem.cite || elem.dateTime)) {
  357.     setInfo("insdel-cite", elem.cite);
  358.     setInfo("insdel-date", elem.dateTime);
  359.     onInsDel = true;
  360.   } 
  361. }
  362.  
  363.  
  364. function checkForQuote(elem, htmllocalname)
  365. {
  366.   if ((htmllocalname === "q" || htmllocalname === "blockquote") && elem.cite) {
  367.     setInfo("quote-cite", elem.cite);
  368.     onQuote = true;
  369.   } 
  370. }
  371.  
  372. function checkForTable(elem, htmllocalname)
  373. {
  374.   if (htmllocalname === "table" && elem.summary) {
  375.     setInfo("misc-tblsummary", elem.summary);
  376.     onTable = true;
  377.   }
  378. }
  379.  
  380. function checkForLang(elem, htmllocalname)
  381. {
  382.   if ((htmllocalname && elem.lang) || elem.getAttributeNS(XMLNS, "lang")) {
  383.     var abbr;
  384.     if (htmllocalname && elem.lang)
  385.       abbr = elem.lang;
  386.     else
  387.       abbr = elem.getAttributeNS(XMLNS, "lang");
  388.         
  389.     setInfo("misc-lang", convertLanguageCode(abbr));
  390.     onLang = true;
  391.   }
  392. }
  393.     
  394. function checkForTitle(elem, htmllocalname)
  395. {
  396.   if (htmllocalname && elem.title) {
  397.     setInfo("misc-title", elem.title);
  398.     onTitle = true;
  399.   }    
  400. }
  401.  
  402. /*
  403.  * Set text of node id to value
  404.  * if value="" the node with specified id is hidden.
  405.  * Node should be have one of these forms
  406.  * <xul:label id="id-text" value=""/>
  407.  * <xul:description id="id-text"/>
  408.  */
  409. function setInfo(id, value)
  410. {
  411.   if (!value) {
  412.     hideNode(id);
  413.     return;
  414.   }
  415.  
  416.   var node = document.getElementById(id+"-text");
  417.  
  418.   if (node.namespaceURI == XULNS && node.localName == "label" ||
  419.      (node.namespaceURI == XULNS && node.localName == "textbox")) {
  420.     node.setAttribute("value",value);
  421.  
  422.   } else if (node.namespaceURI == XULNS && node.localName == "description") {
  423.     while (node.hasChildNodes())
  424.       node.removeChild(node.firstChild);
  425.     node.appendChild(node.ownerDocument.createTextNode(value));
  426.   }
  427. }
  428.  
  429. // Hide node with specified id
  430. function hideNode(id)
  431. {
  432.     var style = document.getElementById(id).getAttribute("style");
  433.     document.getElementById(id).setAttribute("style", "display:none;" + style);
  434. }
  435.  
  436. /*
  437.  * Find <img> or <object> which uses an imagemap.
  438.  * If more then one object is found we can't determine which one
  439.  * was clicked.
  440.  *
  441.  * This code has to be changed once bug 1882 is fixed.
  442.  * Once bug 72527 is fixed this code should use the .images collection.
  443.  */
  444. function getImageForMap(map)
  445. {
  446.   var mapuri = "#" + map.getAttribute("name");
  447.   var multipleFound = false;
  448.   var img;
  449.  
  450.   var list = getHTMLElements(map.ownerDocument, "img");
  451.   for (var i=0; i < list.length; i++) {
  452.     if (list.item(i).getAttribute("usemap") == mapuri) {
  453.       if (img) {
  454.         multipleFound = true;
  455.         break;
  456.       } else {
  457.         img = list.item(i);
  458.         imgType = "img";
  459.       }
  460.     }
  461.   }
  462.  
  463.   list = getHTMLElements(map.ownerDocument, "object");
  464.   for (i = 0; i < list.length; i++) {
  465.     if (list.item(i).getAttribute("usemap") == mapuri) {
  466.       if (img) {
  467.         multipleFound = true;
  468.         break;
  469.       } else {
  470.         img = list.item(i);
  471.         imgType = "object";
  472.       }
  473.     }
  474.   }
  475.  
  476.   if (multipleFound)
  477.     img = null;
  478.  
  479.   return img;
  480. }
  481.  
  482. function getHTMLElements(node, name)
  483. {
  484.   if (htmlMode)
  485.     return node.getElementsByTagName(name);
  486.   return node.getElementsByTagNameNS(XHTMLNS, name);
  487. }
  488.  
  489. // name should be in lower case
  490. function isHTMLElement(node, name)
  491. {
  492.   if (node.nodeType != Node.ELEMENT_NODE)
  493.     return false;
  494.  
  495.   if (htmlMode)
  496.     return !name || node.localName.toLowerCase() == name;
  497.  
  498.   return (!name || node.localName == name) && node.namespaceURI == XHTMLNS;
  499. }
  500.  
  501. // This function coded according to the spec at:
  502. // http://www.bath.ac.uk/~py8ieh/internet/discussion/metadata.txt
  503. function convertLanguageCode(abbr)
  504. {
  505.   if (!abbr) return "";
  506.   var result;
  507.   var language = "";
  508.   var region;
  509.   var is_region_set = false;
  510.   var tokens = abbr.split("-");
  511.  
  512.   if (tokens[0] === "x" || tokens[0] === "i")
  513.   {
  514.     // x and i prefixes mean unofficial ones. So we upper-case the first
  515.     // word and leave the rest.
  516.     tokens.shift();
  517.  
  518.     if (tokens[0])
  519.     {
  520.       // Upper-case first letter
  521.       language = tokens[0].substr(0, 1).toUpperCase() + tokens[0].substr(1);
  522.       tokens.shift();
  523.  
  524.       if (tokens[0])
  525.       {
  526.         // Add on the rest as space-separated strings inside the brackets
  527.         region = tokens.join(" ");
  528.         is_region_set = true;
  529.       }
  530.     }
  531.   }
  532.   else
  533.   {
  534.     // Otherwise we treat the first as a lang, the second as a region
  535.     // and the rest as strings.
  536.     try
  537.     {
  538.       language = gLangBundle.getString(tokens[0].toLowerCase());
  539.     }
  540.     catch (e) 
  541.     {
  542.       // Language not present in lang bundle
  543.       language = tokens[0]; 
  544.     }
  545.  
  546.     tokens.shift();
  547.  
  548.     if (tokens[0])
  549.     {
  550.       try
  551.       {
  552.         // We don't add it on to the result immediately
  553.         // because we want to get the spacing right.
  554.         region = gRegionBundle.getString(tokens[0].toLowerCase());
  555.  
  556.         tokens.shift();
  557.  
  558.         if (tokens[0])
  559.         {
  560.           // Add on the rest as space-separated strings inside the brackets
  561.           region += " " + tokens.join(" ");
  562.         }
  563.       }
  564.       catch (e) 
  565.       {
  566.         // Region not present in region bundle
  567.         region = tokens.join(" ");
  568.       }
  569.  
  570.       is_region_set = true;
  571.     }
  572.   }
  573.  
  574.   if (is_region_set) {
  575.     result = gMetadataBundle.getFormattedString("languageRegionFormat",
  576.                                                 [language, region]);
  577.   } else
  578.     result = language;
  579.  
  580.   return result;
  581. }
  582.  
  583. // Returns the size of the URL in bytes; must be cached and therefore an HTTP or FTP URL
  584. function getSize(url) {
  585.   try
  586.   {
  587.     var cacheEntryDescriptor = httpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  588.     if(cacheEntryDescriptor)
  589.       return cacheEntryDescriptor.dataSize;
  590.   }
  591.   catch(ex) {}
  592.   try
  593.   {
  594.     cacheEntryDescriptor = ftpCacheSession.openCacheEntry(url, Components.interfaces.nsICache.ACCESS_READ, false);
  595.     if (cacheEntryDescriptor)
  596.       return cacheEntryDescriptor.dataSize;
  597.   }
  598.   catch(ex) {}
  599.   return -1;
  600. }
  601.  
  602. function setAlt(elem) {
  603.   var altText = document.getElementById("image-alt-text");
  604.   if (elem.hasAttribute("alt")) {
  605.     if (elem.alt != "") {
  606.       altText.value = elem.alt;
  607.       altText.setAttribute("style","font-style:inherit");
  608.     } else {
  609.       altText.value = gMetadataBundle.getString("altTextBlank");
  610.       altText.setAttribute("style","font-style:italic");
  611.     }
  612.   } else {
  613.     altText.value = gMetadataBundle.getString("altTextMissing");
  614.     altText.setAttribute("style","font-style:italic");
  615.   }
  616. }
  617.